/*
 * Copyright (c) 2022. China Mobile (SuZhou) Software Technology Co.,Ltd. All rights reserved.
 * Lakehouse is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

package com.chinamobile.cmss.lakehouse.api.controller;

import static com.chinamobile.cmss.lakehouse.common.enums.Status.SQL_CONSOLE_EXECUTE_ERROR;
import static com.chinamobile.cmss.lakehouse.common.enums.Status.SQL_CONSOLE_FORMAT_ERROR;
import static com.chinamobile.cmss.lakehouse.common.enums.Status.SQL_CONSOLE_MONITOR_LIST_ERROR;
import static com.chinamobile.cmss.lakehouse.common.enums.Status.SQL_CONSOLE_SQL_ABORT_ERROR;
import static com.chinamobile.cmss.lakehouse.common.enums.Status.SQL_CONSOLE_SQL_QUERY_JOB_ERROR;

import com.chinamobile.cmss.lakehouse.api.dto.SqlQueryParamBean;
import com.chinamobile.cmss.lakehouse.api.exceptions.ApiException;
import com.chinamobile.cmss.lakehouse.api.service.SqlConsoleService;
import com.chinamobile.cmss.lakehouse.common.Constants;
import com.chinamobile.cmss.lakehouse.common.constants.CommonVar;
import com.chinamobile.cmss.lakehouse.common.dto.SqlJobQueryParamDto;
import com.chinamobile.cmss.lakehouse.common.utils.Result;
import com.chinamobile.cmss.lakehouse.dao.entity.UserEntity;

import java.util.List;
import java.util.Map;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.annotations.ApiIgnore;

@Slf4j
@Api(value = "SQL Query Console", protocols = "http")
@RestController
@RequestMapping(value = "/sql-console")
public class SqlConsoleController extends BaseController {

    @Autowired
    private SqlConsoleService sqlQueryService;

    /**
     * format submitted sql
     *
     * @param userId
     * @param sqlQueryParamBean
     * @return
     */
    @RequestMapping(value = "/format", method = RequestMethod.POST)
    @ApiOperation(value = "formatSql", notes = "format sql")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "userId", value = "userId", required = true, paramType = "header", dataType = "String"),
        @ApiImplicitParam(name = "sqlQueryParamBean", value = "sqlQueryParamBean", paramType = "body", dataType = "SqlQueryParamBean")
    })
    @ResponseStatus(HttpStatus.OK)
    @ApiException(SQL_CONSOLE_FORMAT_ERROR)
    public Result getFormattedSql(
        @ApiIgnore @RequestHeader(name = "userId") String userId,
        @RequestBody SqlQueryParamBean sqlQueryParamBean) {
        String querySql = sqlQueryParamBean.getQuerySql();
        String instance = sqlQueryParamBean.getInstance();

        Map<String, Object> result = sqlQueryService.getFormattedSql(userId, querySql, CommonVar.HIVE_DB_TYPE, instance);
        return convertToResult(result);
    }

    /**
     * submit sql to computed engine
     *
     * @param loginUser
     * @param sqlQueryParamBean sqlQueryParamBean
     * @return create result code
     */
    @RequestMapping(value = "/execute", method = RequestMethod.POST)
    @ApiOperation(value = "execute", notes = "execute sql")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "loginUser", value = "loginUser", paramType = "header", dataType = "UserEntity"),
        @ApiImplicitParam(name = "sqlQueryParamBean", value = "sqlQueryParamBean", dataType = "SqlQueryParamBean")
    })
    @ResponseStatus(HttpStatus.OK)
    @ApiException(SQL_CONSOLE_EXECUTE_ERROR)
    public Result execute(
        @ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) UserEntity loginUser,
        @RequestBody SqlQueryParamBean sqlQueryParamBean) {
        Map<String, Object> result = sqlQueryService.executeSql(loginUser, sqlQueryParamBean);
        return convertToResult(result);
    }

    /**
     * abort submitted sql job
     *
     * @param jobIds jobId list
     * @return abort result code
     */
    @RequestMapping(value = "/abort", method = RequestMethod.POST)
    @ApiOperation(value = "abort job", notes = "abort job")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "jobIds", value = "jobIds", required = true, allowMultiple = true, dataType = "String")
    })
    @ResponseStatus(HttpStatus.OK)
    @ApiException(SQL_CONSOLE_SQL_ABORT_ERROR)
    public Result abort(
        @RequestBody List<String> jobIds) {
        Map<String, Object> result = sqlQueryService.abortSql(jobIds);
        return convertToResult(result);
    }

    /**
     * query job execution result
     *
     * @param jobId      job id
     * @param engineType engine type
     * @return
     */
    @RequestMapping(value = "/{jobId}/query", method = RequestMethod.POST)
    @ApiOperation(value = "query job execution result ", notes = "query execution job")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "jobId", value = "JobId", required = true, dataType = "String"),
        @ApiImplicitParam(name = "engineType", value = "Spark、Presto、Flink etd.", dataType = "String")
    })
    @ResponseStatus(HttpStatus.OK)
    @ApiException(SQL_CONSOLE_SQL_QUERY_JOB_ERROR)
    public Result getQueryResult(@PathVariable("jobId") String jobId,
                                 @RequestParam("engineType") String engineType) {
        Map<String, Object> result = sqlQueryService.getQueryResult(jobId, engineType);
        return convertToResult(result);
    }

    /**
     * get sql task monitor list by pagination
     *
     * @param userId
     * @param sqlJobQueryParamDto
     * @return
     */
    @RequestMapping(value = "/monitor/list", method = RequestMethod.POST)
    @ApiOperation(value = "monitor list ", notes = "sql monitor list")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "userId", value = "userId", required = true, paramType = "header", dataType = "String"),
        @ApiImplicitParam(name = "sqlJobQueryParamDto", value = "sqlJobQueryParamDto", paramType = "body", dataType = "SqlJobQueryParamDto")
    })
    @ResponseStatus(HttpStatus.OK)
    @ApiException(SQL_CONSOLE_MONITOR_LIST_ERROR)
    public Result getTaskMonitorList(
        @ApiIgnore @RequestHeader(name = "userId") String userId,
        @RequestBody SqlJobQueryParamDto sqlJobQueryParamDto) {
        sqlJobQueryParamDto.setUserId(userId);
        Map<String, Object> result = sqlQueryService.querySqlTaskInfo(sqlJobQueryParamDto);
        return convertToResult(result);
    }

}
